#include "TcpConnection.hpp"
#include "TcpServer.hpp"
#include "Threadpool.hpp"
#include <iostream>

using std::cout;
using std::endl;

//创建了线程池对象
wd::Threadpool threadpool(4, 10);

class Mytask
{
public:
    Mytask(const string & msg, wd::TcpConnectionPtr conn)
    : _msg(msg)
    , _conn(conn)
    {}

    //process成员函数的执行是在线程池中的某一工作线程完成的
    void process()
    {
        cout << "Mytask::process is running" << endl;
        //decode
        //compute
        //encode
        string response = _msg;
        //send, 发送消息的操作一定要给予一个Tcp连接来完成
        //但该操作不能直接在计算线程中完成，必须要通知
        //IO线程，由IO线程最终完成数据的发送
        //_conn->send(response);
        //为什么要发送数据？
        //因为计算线程处理完毕之后，需要将结果发送回客户端
        //在onMessage函数中不是有send函数吗？为什么还要在这里发送数据？
        //因为send函数是在线程池中的IO线程中执行的
        //而不是在计算线程中执行的//为什么要在计算线程中执行？
        //因为计算线程处理完毕之后，需要将结果发送回客户端
        //而send函数是在线程池中的IO线程中执行的
        //这两个send函数的作用不是一样的吗？
        //是的，这两个send函数的作用是一样的//那为什么还要在这里发送数据？
        //在onMessage函数中不可以用send函数把数据发给客户端吗？
        //可以，但是这样会导致IO线程阻塞，影响并发性能
        //所以需要在计算线程中处理完毕之后，再通知IO线程发送数据
        //那这样不就发送两次了吗？
        //不是的，这里只是将数据发送给IO线程，IO线程再将数据发送给客户端
        _conn->sendInLoop(response);
    }

private:
    string _msg;
    wd::TcpConnectionPtr _conn;
};


void onConnection(wd::TcpConnectionPtr conn)
{
    cout << conn->toString() << " has connected successfully.\n";
}

void onMessage(wd::TcpConnectionPtr conn)
{
    //onMessage函数是执行在IO线程中的
    //在执行该函数对象的过程中，时间都不宜过长，
    //否则会影响并发的执行
    //read
    string msg = conn->receive();//不能阻塞
    cout << "recv: " << msg << endl;

    //decode
    //compute   //业务逻辑的处理时间不宜过长
    //encode    //否则都会造成并发处理不能保证实时性
    //由于业务逻辑的处理过程是很复杂的，那么就可以将其交给
    //计算线程来执行具体的处理流程
    Mytask task(msg, conn);
    threadpool.addTask(std::bind(&Mytask::process, task));
    //当计算线程处理完毕之后，再交给IO线程进行发送
    
    //假设执行的回显服务
    string response = msg;
    //send
    conn->send(response);//时间不宜过长
}

void onClose(wd::TcpConnectionPtr conn)
{
    cout << conn->toString() << " has closed." << endl;
}


int main()
{
    //运行线程池
    threadpool.start();

    cout << "TcpServer Test" << endl;
    wd::TcpServer server(8000);
    server.setAllCallbacks(onConnection, 
                         onMessage,
                         onClose);
    server.start();

    return 0;
}

